{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 作用域"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在函数中，`Python` 从命名空间中寻找变量的顺序如下：\n",
    "\n",
    "- `local function scope`\n",
    "- `enclosing scope`\n",
    "- `global scope`\n",
    "- `builtin scope`\n",
    "\n",
    "例子："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# local 作用域"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def foo(a,b):\n",
    "    c = 1\n",
    "    d = a + b + c"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里所有的变量都在 `local` 作用域。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## global 作用域"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "c = 1\n",
    "def foo(a,b):\n",
    "    d = a + b + c"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里的 `c` 就在 `global` 作用域。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## global 关键词"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 `global` 关键词可以在 `local` 作用域中修改 `global` 作用域的值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "c = 1\n",
    "def foo():\n",
    "    global c\n",
    "    c = 2\n",
    "    \n",
    "print c\n",
    "foo()\n",
    "print c"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "其作用是将 `c` 指向 `global` 中的 `c`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果不加关键词，那么 `local` 作用域的 `c` 不会影响 `global` 作用域中的值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "c = 1\n",
    "def foo():\n",
    "    c = 2\n",
    "    \n",
    "print c\n",
    "foo()\n",
    "print c"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## built-in 作用域"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "def list_length(a):\n",
    "    return len(a)\n",
    "\n",
    "a = [1,2,3]\n",
    "print list_length(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里函数 `len` 就是在 `built-in` 作用域中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function len>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import __builtin__\n",
    "\n",
    "__builtin__.len"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## class 中的作用域"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Global | MyClass\n",
    "---|---\n",
    "`var = 0` <br> `MyClass` <br> `access_class` | `var = 1`<br>`access_class` "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# global\n",
    "var = 0\n",
    "\n",
    "class MyClass(object):\n",
    "    # class variable\n",
    "    var = 1\n",
    "    \n",
    "    def access_class_c(self):\n",
    "        print 'class var:', self.var\n",
    "    \n",
    "    def write_class_c(self):\n",
    "        MyClass.var = 2\n",
    "        print 'class var:', self.var\n",
    "        \n",
    "    def access_global_c(self):\n",
    "        print 'global var:', var\n",
    "    \n",
    "    def write_instance_c(self):\n",
    "        self.var = 3\n",
    "        print 'instance var:', self.var"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Global | MyClass | obj\n",
    "---|---|----\n",
    "`var = 0` <br> `MyClass` <br> [`access_class`] <br> `obj` | `var = 1`<br>`access_class`  |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "obj = MyClass()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "查询 `self.var` 时，由于 `obj` 不存在 `var`，所以跳到 MyClass 中：\n",
    "\n",
    "Global | MyClass | obj\n",
    "---|---|----\n",
    "`var = 0` <br> `MyClass` <br> [`access_class` <br> `self`] <br> `obj` | `var = 1`<br>`access_class`  |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "class var: 1\n"
     ]
    }
   ],
   "source": [
    "obj.access_class_c()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "查询 `var` 直接跳到 `global` 作用域：\n",
    "\n",
    "Global | MyClass | obj\n",
    "---|---|----\n",
    "`var = 0` <br> `MyClass` <br> [`access_class` <br> `self`] <br> `obj` | `var = 1`<br>`access_class`  |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "global var: 0\n"
     ]
    }
   ],
   "source": [
    "obj.access_global_c()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "修改类中的 `MyClass.var`：\n",
    "\n",
    "Global | MyClass | obj\n",
    "---|---|----\n",
    "`var = 0` <br> `MyClass` <br> [`access_class` <br> `self`] <br> `obj` | `var = 2`<br>`access_class`  |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "class var: 2\n"
     ]
    }
   ],
   "source": [
    "obj.write_class_c()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "修改实例中的 `var` 时，会直接在 `obj` 域中创建一个：\n",
    "\n",
    "Global | MyClass | obj\n",
    "---|---|----\n",
    "`var = 0` <br> `MyClass` <br> [`access_class` <br> `self`] <br> `obj` | `var = 2`<br>`access_class`  | `var = 3`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "instance var: 3\n"
     ]
    }
   ],
   "source": [
    "obj.write_instance_c()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "MyClass.var"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`MyClass` 中的 `var` 并没有改变。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 词法作用域"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于嵌套函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = 1\n"
     ]
    }
   ],
   "source": [
    "def outer():\n",
    "    a = 1\n",
    "    def inner():\n",
    "        print \"a =\", a\n",
    "    inner()\n",
    "    \n",
    "outer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果里面的函数没有找到变量，那么会向外一层寻找变量，如果再找不到，则到 `global` 作用域。\n",
    "\n",
    "返回的是函数的情况："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a (1): 1\n"
     ]
    }
   ],
   "source": [
    "def outer():\n",
    "    a = 1\n",
    "    def inner():\n",
    "        return a\n",
    "    return inner\n",
    "    \n",
    "func = outer()\n",
    "\n",
    "print 'a (1):', func()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "func() 函数中调用的 `a` 要从它定义的地方开始寻找，而不是在 `func` 所在的作用域寻找。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
